package cn.uway.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.Map.Entry;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HttpComponentsFileUtils {
	
	    private static Logger logger = LoggerFactory.getLogger(HttpComponentsFileUtils.class);
	
	    //web 应用的接口秘钥
		private static final String appId="67d307e4d1d143d6acd6a33a87d367b9";
		private static final String secretKey="55f2bfde6cd64f00acd2294bbd0963f4";

		 //连接超时时间，默认30秒
	    private static int connectTimeout = 30*1000;
	    
	    //数据传输超时时间，默认30秒
	    private static int socketTimeout = 30*1000;
		
		/**
	     * 
	     * @param url 纯url, 不包含?和&符号的参数
	     * @param parameterMap 装有参数键值对的Map
	     * 本方法支持富文本（HTML转义字符内容）
	     * fileFieldName 文件字段的参数名，如file 或file1 
	     * localFile 要上传的文件 
	     * @return 返回上传结果，JSON格式
	    */
	    public static String uploadFile(String url, Map<String, String> parameterMap, String fileFieldName, File localFile){
	    	if(!parameterMap.containsKey("appId")){
	    		parameterMap.put("appId", appId);		
			}
			String sign = getSignString(parameterMap);
			parameterMap.put("sign", sign);	
	    	CloseableHttpClient httpClient = HttpClients.custom().build();
	   	    logger.debug("=================【http请求】url={}, parameterMap={}", url, parameterMap);
	  	    HttpPost httpPost = new HttpPost(url);
	  	     //设置请求器的配置
	  	    RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();          
	        httpPost.setConfig(requestConfig);
	        String result = "";
	        try {  
		      	MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
		      	Set<Entry<String,String>> entrySet = parameterMap.entrySet();
		      	for(Iterator<Entry<String,String>> it = entrySet.iterator(); it.hasNext(); ){
		      		Entry<String,String> entry = it.next();
		      		multipartEntityBuilder.addTextBody(entry.getKey(), entry.getValue());
		      	}     
		      	multipartEntityBuilder.addBinaryBody(fileFieldName, localFile);
		      	httpPost.setEntity(multipartEntityBuilder.build());
		        HttpResponse response = httpClient.execute(httpPost);
		        HttpEntity entity = response.getEntity();
		        if(entity!=null){
		        	if(response.getStatusLine().getStatusCode()==200){
		        		result = EntityUtils.toString(entity, "UTF-8");
		        	}
		        	else{
		        		logger.warn("http状态码异常,HTTP StatusCode={}", response.getStatusLine().getStatusCode());	
				    }
		        }            
		     } catch (ConnectionPoolTimeoutException e) {
		           logger.error("http连接超时,url="+url,e);
		     } catch (ConnectTimeoutException e) {
		    	      logger.error("http连接超时,url="+url,e);
		     } catch (SocketTimeoutException e) {
		    	     logger.error("http读取数据超时,url="+url,e);
		     } catch (Exception e) {
		    	     logger.error("http请求其它错误,url="+url,e);
		     } 
		     finally {
		    	    if(httpClient!=null){
		    		      try {	 httpClient.close();  } catch ( IOException e ) {	}
		    	    }        	  
		     }
		     logger.debug("=================【http返回】result={}", result);
		     return result;
	    }
	    
	    	    
	    
	    /**
	     * 
	     * @param url 纯url, 不包含?和&符号的参数
	     * @param parameterMap 装有参数键值对的Map
	     * 本方法支持富文本（HTML转义字符内容） 
	     * fileFieldName 文件字段的参数名，如file 或file1 
	     * fileName 接收的文件名
	     * in 文件流
	     * @return 返回上传结果，JSON格式
	    */
	    public static String uploadFile(String url, Map<String, String> parameterMap, String fileFieldName, String fileName, InputStream in){
	    	if(!parameterMap.containsKey("appId")){
	    		parameterMap.put("appId", appId);		
			}
			String sign = getSignString(parameterMap);
			parameterMap.put("sign", sign);	
	    	CloseableHttpClient httpClient = HttpClients.custom().build();
	   	    logger.debug("=================【http请求】url={}, parameterMap={}", url, parameterMap);
	  	    HttpPost httpPost = new HttpPost(url);
	  	     //设置请求器的配置
	  	    RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();          
	        httpPost.setConfig(requestConfig);
	        String result = "";
	        try {  
		      	MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
		      	Set<Entry<String,String>> entrySet = parameterMap.entrySet();
		      	for(Iterator<Entry<String,String>> it = entrySet.iterator(); it.hasNext(); ){
		      		Entry<String,String> entry = it.next();
		      		multipartEntityBuilder.addTextBody(entry.getKey(), entry.getValue());
		      	}     
		      	multipartEntityBuilder.addBinaryBody(fileFieldName, in, ContentType.APPLICATION_OCTET_STREAM, fileName);
		      	httpPost.setEntity(multipartEntityBuilder.build());
		        HttpResponse response = httpClient.execute(httpPost);
		        HttpEntity entity = response.getEntity();
		        if(entity!=null){
		        	if(response.getStatusLine().getStatusCode()==200){
		        		result = EntityUtils.toString(entity, "UTF-8");
		        	}
		        	else{
		        		logger.warn("http状态码异常,HTTP StatusCode={}", response.getStatusLine().getStatusCode());	
				    }
		        }
		        
		     } catch (ConnectionPoolTimeoutException e) {
		           logger.error("http连接超时,url="+url,e);
		     } catch (ConnectTimeoutException e) {
		    	      logger.error("http连接超时,url="+url,e);
		     } catch (SocketTimeoutException e) {
		    	     logger.error("http读取数据超时,url="+url,e);
		     } catch (Exception e) {
		    	     logger.error("http请求其它错误,url="+url,e);
		     } 
		     finally {
		    	    if(httpClient!=null){
		    		      try {	 httpClient.close();  } catch ( IOException e ) {	}
		    	    }        	  
		     }
		     logger.debug("=================【http返回】result={}", result);
		     return result;
	    }
	    
	    
	    public static  String  getSignString(Map<String,String> paramMap){
			Map<String, String> paramTreeMap = new TreeMap<String, String>();
			paramTreeMap.putAll(paramMap); //使用treeMap对参数进行排序
			StringBuilder sb = new StringBuilder();
	    	Iterator<String> it = paramTreeMap.keySet().iterator();
	    	try{
	    		while (it.hasNext()) {
	    			String key = it.next();
	    			String val = paramTreeMap.get(key);
	    			
	    			if(key!=null && !"".endsWith(key.trim()) && !"sign".equals(key)){
	    				if(val!=null && !"".equals(val.trim())){
	    					//计算sign的时候，需要使用中文，如果传入的中文参数被编码成了%AB%DE%2F,则需要decode还原
	    					sb.append(key).append( URLDecoder.decode(val, "utf-8") );  
	    				}	
	    			}			
	    		}
	    	}
	    	catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			sb.append(secretKey);
			return MD5Encoder.encode(sb.toString());
		}	
	    
	    public static void main(String[] args){	  
	    	String url ="http://192.168.0.226:8080/fileService/v1/file/upload";
	    	String folderName = "test";
			Map<String, String> parameterMap = new HashMap<String, String>();
			parameterMap.put("folderName", folderName);
	    	String json;
			try {
				json = uploadFile(url, parameterMap, "file", "ttt.png", new FileInputStream("d:/backdround-img.png"));
				System.out.println(json);
			}
			catch (FileNotFoundException e) {
				e.printStackTrace();
			}
	    	
	    }
}
